package com.cwd.arm.domain.repository.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.cwd.arm.common.enums.ErrorEnum;
import com.cwd.arm.common.enums.RoleTypeEnum;
import com.cwd.arm.common.exception.ArmException;
import com.cwd.arm.common.util.DateUtil;
import com.cwd.arm.common.util.SessionUtil;
import com.cwd.arm.domain.entity.*;
import com.cwd.arm.domain.repository.ProjectMonthAmountTotalRepository;
import com.cwd.arm.domain.repository.ProjectRepository;
import com.cwd.arm.domain.service.AmountAppService;
import com.cwd.arm.infrastructure.dao.ProjectDao;
import com.cwd.arm.infrastructure.dao.ReceiveNodeDao;
import com.cwd.arm.infrastructure.dao.ReceiveRecordDao;
import com.cwd.arm.infrastructure.po.ProjectPo;
import com.cwd.arm.infrastructure.po.ReceiveNodePo;
import com.cwd.arm.infrastructure.po.ReceiveRecordPo;
import com.cwd.arm.infrastructure.po.RolePo;
import com.cwd.arm.infrastructure.query.ReceiveNodeDaoQuery;
import com.cwd.arm.infrastructure.query.ReceiveRecordDaoQuery;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

/**
 * Description:项目
 * Created on 2021年11月16日
 *
 * @author yan
 */
@Repository
public class ProjectRepositoryImpl implements ProjectRepository {

    @Autowired
    private ProjectDao dao;

    @Autowired
    private ProjectMonthAmountTotalRepository projectMonthAmountTotalRepository;

    @Autowired
    private AmountAppService amountAppService;

    @Autowired
    private ReceiveNodeDao receiveNodeDao;

    @Autowired
    private ReceiveRecordDao receiveRecordDao;

    @Override
    public Long save(ProjectEntity entity) {
        ProjectPo projectPo = convertToProjectPo(entity);
        dao.save(projectPo);
        return projectPo.getId();
    }

    @Override
    public void update(ProjectEntity entity) {
        ProjectPo projectPo = dao.getById(entity.getId());
        if (entity.needFinRole(projectPo.getCloseAmount())) {
            if (!SessionUtil.hasFinAuth()) {
                throw new ArmException(ErrorEnum.AUTH_ERROR, "需要拥有财务调整权限才能修改结算金额");
            }
        }
        entity.calUnrevicedAmount();
        amountAppService.calByContractAmount(entity.getId(), entity.getContractAmount());
        dao.updateById(convertToProjectPo(entity));
    }

    private static boolean isADMINOrFIN( List<RolePo> rolePoList){
        if(CollectionUtils.isNotEmpty(rolePoList)){
            for(RolePo rolePo : rolePoList){
                if(rolePo.getId().toString().equals(RoleTypeEnum.ADMIN.getCode())
                        || rolePo.getId().toString().equals(RoleTypeEnum.FIN.getCode())){
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void del(Long id) {
        ProjectEntity entity = buildProjectEntity(id);
        if (entity.canDel()) {
            dao.removeById(id);
        }
    }

    @Override
    public void addNode(ProjectEntity entity, List<ReceiveNodeEntity> receiveNodeEntityList) {
        entity.addNode(receiveNodeEntityList);
        updateDataByDiffNode(entity);
    }

    @Override
    public void updateNode(ProjectEntity entity, ReceiveNodeEntity oldReceiveNodeEntity, ReceiveNodeEntity receiveNodeEntity) {
        entity.updateNode(oldReceiveNodeEntity, receiveNodeEntity);
        updateDataByDiffNode(entity);
    }

    @Override
    public void delNode(ProjectEntity entity, ReceiveNodeEntity receiveNodeEntity) {
        entity.delNode(receiveNodeEntity);
        updateDataByDiffNode(entity);
    }

    @Override
    public void addConfirmIncome(ProjectEntity entity, ConfirmIncomeEntity confirmIncomeEntity) {
        entity.addConfirmIncome(confirmIncomeEntity);
        updateDataByDiffConfirmIncome(entity);
    }

    @Override
    public void updateConfirmIncome(ProjectEntity entity, ConfirmIncomeEntity oldConfirmIncomeEntity, ConfirmIncomeEntity newConfirmIncomeEntity) {
        entity.updateConfirmIncome(oldConfirmIncomeEntity, newConfirmIncomeEntity);
        updateDataByDiffConfirmIncome(entity);
    }

    @Override
    public void delConfirmIncome(ProjectEntity entity, ConfirmIncomeEntity confirmIncomeEntity) {
        entity.delConfirmIncome(confirmIncomeEntity);
        updateDataByDiffConfirmIncome(entity);
    }

    @Override
    public void addPay(ProjectEntity entity, PayEntity payEntity) {
        entity.addPay(payEntity);
        updateDataByDiffPay(entity);
    }

    @Override
    public void updatePay(ProjectEntity entity, PayEntity oldPayEntity, PayEntity newPayEntity) {
        entity.updatePay(oldPayEntity, newPayEntity);
        updateDataByDiffPay(entity);
    }

    @Override
    public void delPay(ProjectEntity entity, PayEntity PayEntity) {
        entity.delPay(PayEntity);
        updateDataByDiffPay(entity);
    }

    @Override
    public void updateReceiveCycle(Long id) {
        ReceiveNodeDaoQuery daoQuery = new ReceiveNodeDaoQuery();
        daoQuery.setProjectId(id);
        List<ReceiveNodePo> poList = receiveNodeDao.selectByQuery(daoQuery);
        List<Integer> diffDayList = new ArrayList<>();
        for(ReceiveNodePo receiveNodePo : poList){
            ReceiveRecordDaoQuery receiveRecordDaoQuery = new ReceiveRecordDaoQuery();
            receiveRecordDaoQuery.setReceiveNodeId(receiveNodePo.getId());
            List<ReceiveRecordPo> receiveRecordPoList = receiveRecordDao.selectByQuery(receiveRecordDaoQuery);
            if(CollectionUtils.isNotEmpty(receiveRecordPoList)){
                for(ReceiveRecordPo receiveRecordPo : receiveRecordPoList){
                    diffDayList.add(DateUtil.differentDaysByMillisecond(receiveNodePo.getEndDate(),receiveRecordPo.getReceiveDate()));
                }
            }
        }
        Double day = diffDayList.stream().mapToInt(i->i).average().getAsDouble();
        ProjectPo projectPo = new ProjectPo();
        projectPo.setId(id);
        projectPo.setReceiveCycle(day.intValue());
        dao.updateById(projectPo);

    }

    /**
     * 因为节点信息变更而修改相关联的数据
     *
     * @param entity
     */
    private void updateDataByDiffNode(ProjectEntity entity) {
        update(entity);
        calMonthTotalByDiffNode(entity);
    }

    /**
     * 因为确认收入信息变更而修改相关联的数据
     *
     * @param entity
     */
    private void updateDataByDiffConfirmIncome(ProjectEntity entity) {
        update(entity);
        calMonthTotalByDiffConfirmIncome(entity);
    }

    /**
     * 因为确认收入信息变更而修改相关联的数据
     *
     * @param entity
     */
    private void updateDataByDiffPay(ProjectEntity entity) {
        update(entity);
        calMonthTotalByDiffPay(entity);
    }

    /**
     * 因为节点信息变更而计算月统计信息
     *
     * @param entity
     */
    private void calMonthTotalByDiffNode(ProjectEntity entity) {
        List<ProjectMonthAmountTotalEntity> projectMonthAmountTotalEntityList
                = entity.getDiffMonthAmountByDiffNode();
        projectMonthAmountTotalRepository.save(projectMonthAmountTotalEntityList);
    }

    /**
     * 因为节点信息变更而计算月统计信息
     *
     * @param entity
     */
    private void calMonthTotalByDiffConfirmIncome(ProjectEntity entity) {
        List<ProjectMonthAmountTotalEntity> projectMonthAmountTotalEntityList
                = entity.getDiffMonthAmountByDiffConfirmIncome();
        projectMonthAmountTotalRepository.save(projectMonthAmountTotalEntityList);
    }

    private void calMonthTotalByDiffPay(ProjectEntity entity) {
        List<ProjectMonthAmountTotalEntity> projectMonthAmountTotalEntityList
                = entity.getDiffMonthAmountByDiffPay();
        projectMonthAmountTotalRepository.save(projectMonthAmountTotalEntityList);
    }


    private ProjectPo convertToProjectPo(ProjectEntity entity) {
        ProjectPo ProjectPo = new ProjectPo();
        BeanUtils.copyProperties(entity, ProjectPo);
        ProjectPo.setCalAmount(entity.getCalAmount());
        return ProjectPo;
    }

    @Override
    public ProjectEntity buildProjectEntity(Long id) {
        ProjectPo projectPo = dao.getById(id);
        ProjectEntity entity = new ProjectEntity();
        BeanUtils.copyProperties(projectPo, entity);
        return entity;
    }

}
